
#ifndef __HTTP_REQUEST_H__
#define __HTTP_REQUEST_H__

#include <string>
#include <vector>
#include "base/RefBase.h"
#include "ZScheduler.h"

namespace ZuiLib {

class ZHttpClient;
class ZHttpResponse;

typedef void (ZSchedulerBase::*SEL_HttpResponse)(ZHttpClient* client, ZHttpResponse* response);
#define httpresponse_selector(_SELECTOR) (SEL_HttpResponse)(&_SELECTOR)


class ZHttpRequest : public ZRefCountedBase
{
public:
	ZUI_CLASS_NAME("zui.HttpRequest");

    /** Use this enum type as param in setReqeustType(param) */
    enum Type
    {
        TYPE_GET,
        TYPE_POST,
        TYPE_PUT,
        TYPE_DELETE,
        TYPE_UNKNOWN,
    };
    
    /** Constructor
        Because HttpRequest object will be used between UI thead and network thread,
        requestObj->autorelease() is forbidden to avoid crashes in AutoreleasePool
        new/retain/release still works, which means you need to release it manually
        Please refer to HttpRequestTest.cpp to find its usage
     */
    ZHttpRequest()
    {
        _requestType = TYPE_UNKNOWN;
        _url.clear();
        _requestData.clear();
        _tag.clear();
        _pTarget = NULL;
        _pSelector = NULL;
        _pUserData = NULL;
    };
    
    /** Destructor */
    virtual ~ZHttpRequest()
    {
        if (_pTarget)
        {
            _pTarget->Release();
        }
    };
    
            
    // setter/getters for properties
     
    /** Required field for HttpRequest object before being sent.
        kHttpGet & kHttpPost is currently supported
     */
    inline void setRequestType(Type type)
    {
        _requestType = type;
    };
    /** Get back the kHttpGet/Post/... enum value */
    inline Type getRequestType()
    {
        return _requestType;
    };
    
    /** Required field for HttpRequest object before being sent.
     */
    inline void setUrl(const char* url)
    {
        _url = url;
    };
    /** Get back the setted url */
    inline const char* getUrl()
    {
        return _url.c_str();
    };
    
    /** Option field. You can set your post data here
     */
    inline void setRequestData(const char* buffer, size_t len)
    {
        _requestData.assign(buffer, buffer + len);
    };
    /** Get the request data pointer back */
    inline char* getRequestData()
    {
        if(_requestData.size() != 0)
            return &(_requestData.front());

        return NULL;
    }
    /** Get the size of request data back */
    inline size_t getRequestDataSize()
    {
        return _requestData.size();
    }
    
    /** Option field. You can set a string tag to identify your request, this tag can be found in HttpResponse->getHttpRequest->getTag()
     */
    inline void setTag(const char* tag)
    {
        _tag = tag;
    };
    /** Get the string tag back to identify the request. 
        The best practice is to use it in your MyClass::onMyHttpRequestCompleted(sender, HttpResponse*) callback
     */
    inline const char* getTag()
    {
        return _tag.c_str();
    };
    
    /** Option field. You can attach a customed data in each request, and get it back in response callback.
        But you need to new/delete the data pointer manully
     */
    inline void setUserData(void* pUserData)
    {
        _pUserData = pUserData;
    };
    /** Get the pre-setted custom data pointer back.
        Don't forget to delete it. HttpClient/HttpResponse/HttpRequest will do nothing with this pointer
     */
    inline void* getUserData()
    {
        return _pUserData;
    };
    
    /** Required field. You should set the callback selector function at ack the http request completed
     */

    inline void setResponseCallback(ZSchedulerBase* pTarget, SEL_HttpResponse pSelector)
    {
		if (_pTarget)
		{
			_pTarget->Release();
			_pTarget=NULL;
		}
		
        _pTarget = pTarget;
        _pSelector = pSelector;
        
        if (_pTarget)
        {
            _pTarget->AddRef();
        }
    }
    
    
    /** Get the target of callback selector funtion, mainly used by HttpClient */
    inline ZSchedulerBase* getTarget()
    {
        return _pTarget;
    }

    /** Get the selector function pointer, mainly used by HttpClient */
    inline SEL_HttpResponse getSelector()
    {
        return _pSelector;
    }
    
    /** Set any custom headers **/
    inline void setHeaders(const std::vector<std::string>& pHeaders)
   	{
   		_headers=pHeaders;
   	}
   
    /** Get custom headers **/
   	inline const std::vector<std::string>& getHeaders()
   	{
   		return _headers;
   	}
    
protected:
    // properties
    Type                        _requestType;    /// kHttpRequestGet, kHttpRequestPost or other enums
    std::string                 _url;            /// target url that this request is sent to
    std::vector<char>           _requestData;    /// used for POST
    std::string                 _tag;            /// user defined tag, to identify different requests in response callback
    ZSchedulerBase*             _pTarget;        /// callback target of pSelector function
    SEL_HttpResponse            _pSelector;      /// callback function, e.g. MyLayer::onHttpResponse(HttpClient *sender, HttpResponse * response)
    void*                       _pUserData;      /// You can add your customed data here 
    std::vector<std::string>    _headers;		 /// custom http headers
};

typedef ZRefCountedPtr<ZHttpRequest> ZHttpRequestPtr;

}


#endif //__HTTP_REQUEST_H__
